﻿using System.Linq;
using CardPlay.Model.CardModel;
using CardPlay.Model.GameModel;
using CardPlay.Model.GameModel.Actions;
using CardPlay.Model.GameModel.Presentation;
using CardPlay.Model.Layout;
using CardPlay.Model.Primitives;

namespace CardPlay.DemoPack.Games
{
    [Game("260E4C63-37BA-4494-9EBD-238AFB50955B", LevelOfDifficulty.Easy, LevelOfSkill.MostlyChance, DurationOfPlay.Within5To10Minutes)]
    public class Osmosis : StandardCardGame
    {
        public Osmosis()
        {
            NamesOfAdditionalPiles.AddRange(new[] {Stock, Waste});

            TotalTableaus = 4;
            TableauDealPattern = "3 down;1 up";
            TableauBuildSequence = CardFaceSequence.None;
        }

        public override ILayoutSite CreatePresentation(IPresentationContext presentation)
        {
            var metrics = presentation.Metrics;

            var root = new SideBySideLayout
            {
                MaximumSpacing = metrics.MaxSpacingAcross,
                MinimumSpacing = metrics.MaxSpacingAcross,
                HorizontalContentAlignment = HorizontalAlignment.Center,
                VerticalContentAlignment = VerticalAlignment.Stretch
            };

            var stockWaste = new SideBySideLayout { Direction = SpreadDirection.Vertical };
            root.Add(stockWaste);

            stockWaste.Add(presentation.CreatePileVisual(Stock, CreateStockStyle(metrics)));
            stockWaste.Add(presentation.CreatePileVisual(Waste, presentation.StyleForWaste()));

            var reserves = presentation.CreateColumnLayout();
            root.Add(reserves);

            presentation.AddPiles(reserves, NamesOfTableaus,
                new VisualTraits
                {
                    Arrangement = CardArrangement.StackLeftToRight,
                    MinimumSize = new Size(metrics.CardSize.Width * 3 / 2, metrics.CardSize.Height)
                });

            var foundations = presentation.CreateColumnLayout();
            root.Add(foundations);

            var style = StandardStyles.Foundation;
            style.Arrangement = CardArrangement.StackLeftToRight;
            style.MinimumSize = new Size(metrics.MaxStackingSize.Width, metrics.CardSize.Height);
            style.UpdateBaseCues = UpdateFoundationHints;

            presentation.AddPiles(foundations, NamesOfFoundations, style);

            return root;
        }

        private void UpdateFoundationHints(CardPile pile, BaseCues baseCues)
        {
            baseCues.Rank = FoundationBaseRank;
            baseCues.Suits = CardFace.AllSuits.Except(this.NonEmptyPilesNamed(AnyFoundation).Select(foundation => foundation.BottomCard.Suit)).ToArray();
        }

        protected string TableauDealPattern { get; set; }

        protected override void PrepareDealScript(DealScript script)
        {
            script.DealCardTo(Foundation1);
            script.DealToEach(NamesOfTableaus, TableauDealPattern);
            script.DealRemainingFaceDownTo(Stock);
        }

        protected override bool AllowedToPickupAtTableau(RemovePileAction action)
        {
            return action.IsActingOnFaceUpTopCard();
        }

        protected override bool AllowedToBuildFoundation(MovePileAction action)
        {
            if (!action.Location.Matches(AnyFoundation)) return false;

            var firstFoundation = action.CardGame[Foundation1];

            // For foundations 2-4, ensure that the previous pile is higher than the
            // target pile.

            if (action.TargetPile != firstFoundation)
            {
                var precedingFoundation = action.CardGame.FindPreviousCardPile(action.TargetPile);

                if (precedingFoundation == null || !IsBuildAllowedOnAdjacentFoundation(action, precedingFoundation))
                    return false;
            }

            return action.IsBuilding(CardFaceSequence.SameSuit, firstFoundation.BottomCard.Rank);
        }

        protected virtual bool IsBuildAllowedOnAdjacentFoundation(MovePileAction action, CardPile precedingFoundation)
        {
            return precedingFoundation.Contains(action.PileBeingMoved.BottomCard.Rank);
        }

        protected override void OnTransactionEnding()
        {
            this.FlipFaceDownTopCardsInPilesMatching(AnyTableau);
        }
    }
}
